package com.jl.card.gp;

import java.util.Arrays;

import com.jl.card.JL;
import com.jl.util.HexUtil;

public class SCP02 extends SCP{

	byte[] bMACSession = new byte[24];
	byte[] bDEKSession = new byte[24];
	byte[] ICV = new byte[8];

	public SCP02() {
		this.protocol = SCP_02;
	}

	@Override
	public void generateSessionKeys() {
		// Generate DerivationData
		byte[] bDerivation = new byte[16];
		byte[] bTmp = null;

		System.arraycopy(cardRand, 0, bDerivation, 2, 2);
		bDerivation[0] = (byte) 0x01;

		bDerivation[1] = (byte) 0x82;
		bTmp = Util.tripleDESCBC(gpKey.getENC(), bDerivation, false);
		System.arraycopy(bTmp, 0, bENCSession, 0, 16);
		System.arraycopy(bTmp, 0, bENCSession, 16, 8);

		bDerivation[1] = (byte) 0x01;
		bTmp = Util.tripleDESCBC(gpKey.getMAC(), bDerivation, false);
		System.arraycopy(bTmp, 0, bMACSession, 0, 16);
		System.arraycopy(bTmp, 0, bMACSession, 16, 8);

		bDerivation[1] = (byte) 0x81;
		bTmp = Util.tripleDESCBC(gpKey.getDEK(), bDerivation, false);
		System.arraycopy(bTmp, 0, bDEKSession, 0, 16);
		System.arraycopy(bTmp, 0, bDEKSession, 16, 8);
	}

	@Override
	public byte[] wrap(byte[] cmd) {
		if (cmd[0] == (byte) 0x84 && cmd[1] == (byte) 0x82) {

		} else if (level == JL.GP_AUTH_LEVEL_MAC
				|| level == JL.GP_AUTH_LEVEL_ENC_MAC) {
			cmd[0] |= 0x04;
		} else if (level == JL.GP_AUTH_LEVEL_NO) {
			return cmd;
		}
		int len = cmd.length;
		if (len > 250)
			return null;
		if (len == 5)
			cmd[4] = (byte) 0;
		if (len == 4) {
			byte[] temp = new byte[5];
			System.arraycopy(cmd, 0, temp, 0, 4);
			cmd = temp;
		}
		cmd[4] = (byte) ((cmd[4] & 0xFF) + 8);
		ICV = Util.singleDESPlusFinalTripleDES_MAC(bMACSession, cmd, ICV);
		cmd = HexUtil.contacByteArray(cmd, ICV);
		ICV = Util.DESCBC(Arrays.copyOfRange(bMACSession, 0, 8), ICV, false);
		if (level == JL.GP_AUTH_LEVEL_ENC_MAC) {
			// With data field in command APDU
			byte[] temp = null;
			int il = 0;
			if (cmd[4] != (byte) 8) {
				len = cmd.length - 5 - 8;
				il = (len + 8) & 0xF8;
				temp = new byte[il];
				temp[len] = (byte) 0x80;
				System.arraycopy(cmd, 5, temp, 0, len);
			}
			// encrypto data field
			temp = Util.tripleDESCBC(bENCSession, temp, false);
			byte[] bTmp1 = new byte[5 + temp.length + 8];
			System.arraycopy(cmd, 0, bTmp1, 0, 4);
			System.arraycopy(temp, 0, bTmp1, 5, temp.length);
			System.arraycopy(cmd, cmd.length - 8, bTmp1, bTmp1.length - 8, 8);
			cmd = bTmp1;
			cmd[4] = (byte) (cmd.length - 5);
		}
		return cmd;
	}

	@Override
	public byte[] unwrap(byte[] res) {
		return res;
	}
}